/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package arithclientrpc;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;

/**
 * Classe que representa a aplicação cliente da aplicação distribuída cliente-servidor
 * @author MCAS
 * 
 */
public class ClientRPC {

    /**
     * Expressão principal passada pelo usuário
     */
    private static String mainExpression;
    /**
     * Porta de comunicação passada pelo usuário
     */
    private static int port = 0;
    /**
     * Endereço do servidor passado pelo usuário
     */
    private static String serverAddress = null;
    /**
     * Resultado final da expressão principal
     */
    private static String finalResult = null;
    /**
     * Mensagem de erro quando ocorre estouro ou divisão por zero
     */
    private static final String ERROR_MESSAGE = "Divisão por zero ou número de " +
            "casas decimais maiores que o suportado (10 casas)";
    /**
     * Mensagem de erro informando o tempo de resposta excedido
     */
    private static final String TIMEOUT = "Tempo de resposta excedido.";
    /**
     * Referencia a tela de configuração
     */
    private static InitialFrame view;
    
    /**
     * Este método realiza a conexão com uma aplicação servidor remota
     * @param fooExpression uma expressão aritmetica parcial
     * @return retorna uma string com o valor da expressão passada como parametro
     * @throws java.io.IOException exceção relacionada ao timeout da aplicação cliente
     */
    public static String connect(String fooExpression) throws IOException {


        DatagramSocket socket = null;

        DatagramPacket reply = null;

        String result = null;

        try {
            socket = new DatagramSocket();

            InetAddress address = InetAddress.getByName(serverAddress);

            DatagramPacket packet = new DatagramPacket(fooExpression.getBytes(),
                    fooExpression.getBytes().length, address, port);

            socket.setSoTimeout(10000); //valor arbitrário

            socket.send(packet);

            byte[] buffer = new byte[1024];

            reply = new DatagramPacket(buffer, buffer.length);

            socket.receive(reply);

            result = new String(reply.getData()).substring(reply.getOffset(), reply.getLength());

            if (result.equalsIgnoreCase("null")) {
                result = ERROR_MESSAGE;
            }

            System.out.println(result);

            socket.close();

        } catch (SocketException ex) {
            Logger.getLogger(ClientRPC.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnknownHostException ex) {
            JOptionPane.showMessageDialog(null, "Endereço inválido ou desconhecido " +
                    "para o servidor", "Erro", JOptionPane.ERROR_MESSAGE);
        }
        return result;

    }

    /**
     * Este método realiza o calculo de uma expressão, enviando par por par de operandos
     * para a aplicação servidor realizar os cálculos. 
     */
    public static void calcule() {
        String lastPartialResult = null;
        String partialExpression = "";

        try {
            if (mainExpression.charAt(0) == '-' || mainExpression.charAt(0) == '+') {
                int count = 0;
                for (int i = 1; i < mainExpression.length(); i++) {
                    if (mainExpression.charAt(i) == '-' || mainExpression.charAt(i) == '+'
                            || mainExpression.charAt(i) == '*' || mainExpression.charAt(i) == '/') {
                        if (count == 0) {
                            count++;
                            int k = i + 1;
                            while (k < mainExpression.length() && mainExpression.charAt(k) != '-'
                                    && mainExpression.charAt(k) != '+'
                                    && mainExpression.charAt(k) != '*'
                                    && mainExpression.charAt(k) != '/') {
                                k++;
                            }

                            partialExpression = partialExpression +
                                    mainExpression.charAt(0) + mainExpression.substring(1, i) +
                                    mainExpression.charAt(i) + mainExpression.substring(i + 1, k);
                            
                            lastPartialResult = connect(partialExpression);
                       
                        } else {
                            int k = i + 1;
                            while (k < mainExpression.length() && mainExpression.charAt(k) != '-'
                                    && mainExpression.charAt(k) != '+'
                                    && mainExpression.charAt(k) != '*'
                                    && mainExpression.charAt(k) != '/') {
                                k++;
                            }

                            partialExpression = lastPartialResult + mainExpression.charAt(i) +
                                    mainExpression.substring(i + 1, k);
                            
                            lastPartialResult = connect(partialExpression);
                            
                        }
                    }
                }

            } else if (mainExpression.charAt(0) == '*' || mainExpression.charAt(0) == '/') {
                JOptionPane.showMessageDialog(null, "Expressão Ilegal", "Erro", JOptionPane.ERROR);
                JOptionPane.showMessageDialog(null, "Este cliente será fechado", "Exit", JOptionPane.INFORMATION_MESSAGE);
                System.exit(1);
            } else {
                int count = 0;
                for (int i = 0; i < mainExpression.length(); i++) {
                    if (mainExpression.charAt(i) == '-' || mainExpression.charAt(i) == '+'
                            || mainExpression.charAt(i) == '*' || mainExpression.charAt(i) == '/') {
                        if (count == 0) {
                            count++;
                            int k = i + 1;
                            while (k < mainExpression.length() 
                                    && mainExpression.charAt(k) != '-'
                                    && mainExpression.charAt(k) != '+'
                                    && mainExpression.charAt(k) != '*'
                                    && mainExpression.charAt(k) != '/') {
                                k++;
                            }

                            partialExpression = partialExpression +
                                    mainExpression.substring(0, i) +
                                    mainExpression.charAt(i) +
                                    mainExpression.substring(i + 1, k);
                            
                            lastPartialResult = connect(partialExpression);
                            

                        } else {
                            int k = i + 1;
                            while (k < mainExpression.length() 
                                    && mainExpression.charAt(k) != '-'
                                    && mainExpression.charAt(k) != '+'
                                    && mainExpression.charAt(k) != '*'
                                    && mainExpression.charAt(k) != '/') {
                                k++;
                            }

                            partialExpression = lastPartialResult + mainExpression.charAt(i) + mainExpression.substring(i + 1, k);
                            
                            lastPartialResult = connect(partialExpression);
                            
                        }
                    }
                }
            }

        } catch (IOException io) {
            int result = JOptionPane.showConfirmDialog(null, "Tempo de " +
                    "resposta do servidor expirou (10s). Deseja " +
                    "tentar novamente?", "Timeout Error",
                    JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE);
            if (result == JOptionPane.YES_OPTION) {
                calcule();
            } else if (result == JOptionPane.NO_OPTION) {
                JOptionPane.showMessageDialog(null, "A aplicação será fechada", "Exit", JOptionPane.CLOSED_OPTION);
                System.exit(1);
            }
        }
        finalResult = lastPartialResult;
        if(finalResult != null)
            System.out.println("Resultado final da operação: "+finalResult);
    }

    /**
     * @return the mainExpression
     */
    public static String getExpression() {
        return mainExpression;
    }

    /**
     * @param mainExpression the mainExpression to set
     */
    public static void setExpression(String expression) {
        ClientRPC.mainExpression = expression;
    }

    /**
     * @return the port
     */
    public static int getPort() {
        return port;
    }

    /**
     * @param aPort the port to set
     */
    public static void setPort(int aPort) {
        port = aPort;
    }

    /**
     * @return the serverAddress
     */
    public static String getServerAddress() {
        return serverAddress;
    }

    /**
     * @param aServerAddress the serverAddress to set
     */
    public static void setServerAddress(String aServerAddress) {
        serverAddress = aServerAddress;
    }

    /**
     * @return the finalResult
     */
    public static String getResult() {
        return finalResult;
    }

    /**
     * @param aResult the finalResult to set
     */
    public static void setResult(String aResult) {
        finalResult = aResult;
    }

    /**
     * @return the view
     */
    public static InitialFrame getView() {
        return view;
    }

    /**
     * @param aView the view to set
     */
    public static void setView(InitialFrame aView) {
        view = aView;
    }
}
